import 'dart:io';
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:http/http.dart' as http;
import 'package:path/path.dart' as path;
import '../../../config/app_config.dart';
import '../../../models/api_response.dart';
import '../../../models/chunk_upload.dart';
import '../../../services/auth_service.dart';

/// 分片上传客户端，负责处理API调用
class ChunkUploadClient {
  /// API服务器地址
  static String get baseUrl => AppConfig.apiServerUrl;

  /// 单例模式实现
  static final ChunkUploadClient _instance = ChunkUploadClient._internal();
  factory ChunkUploadClient() => _instance;
  ChunkUploadClient._internal();

  /// 初始化分片上传
  Future<ApiResponse<ChunkUploadInitResponse>> initChunkUpload({
    required String fileName,
    required int fileSize,
    int chunkSize = 5 * 1024 * 1024,
    required String mimeType,
    int directoryId = 0,
  }) async {
    var uri = Uri.parse('$baseUrl/chunk-upload/init');

    try {
      // 获取认证头
      var headers = await AuthService.getAuthHeaders();
      headers['Content-Type'] = 'application/json';

      // 准备请求体
      final requestBody = {
        'file_name': fileName,
        'file_size': fileSize,
        'chunk_size': chunkSize,
        'mime_type': mimeType,
        'directory_id': directoryId,
      };

      var response = await http.post(
        uri,
        headers: headers,
        body: json.encode(requestBody),
      );

      // 如果返回401，尝试刷新令牌并重试
      if (response.statusCode == 401) {
        print('令牌已过期，尝试刷新...');
        await AuthService.refreshToken();

        // 使用新令牌重试请求
        headers = await AuthService.getAuthHeaders();
        headers['Content-Type'] = 'application/json';

        response = await http.post(
          uri,
          headers: headers,
          body: json.encode(requestBody),
        );
      }

      final responseData = json.decode(utf8.decode(response.bodyBytes));

      // 处理错误响应
      if (response.statusCode != 200) {
        final errorMessage =
            responseData['detail'] ?? responseData['message'] ?? '未知错误';
        throw Exception(errorMessage);
      }

      final apiResponse = ApiResponse<ChunkUploadInitResponse>.fromJson(
        responseData,
        (data) =>
            ChunkUploadInitResponse.fromJson(data as Map<String, dynamic>),
      );

      if (apiResponse.isSuccess) {
        return apiResponse;
      } else {
        throw Exception(apiResponse.message);
      }
    } catch (e) {
      print('初始化分片上传失败: $e');
      rethrow;
    }
  }

  /// 上传分片
  Future<ApiResponse<ChunkUploadResponse>> uploadChunk({
    required String taskId,
    required int chunkNumber,
    required dynamic chunkData,
    required String filePath,
    required int start,
    required int end,
  }) async {
    var uri = Uri.parse('$baseUrl/chunk-upload/upload-chunk').replace(
      queryParameters: {
        'task_id': taskId,
        'chunk_number': chunkNumber.toString(),
      },
    );

    try {
      print('准备上传分片到: $uri');
      // 获取认证头
      var headers = await AuthService.getAuthHeaders();
      print('获取到认证头: $headers');

      // 创建multipart请求
      var request = http.MultipartRequest('POST', uri);
      request.headers.addAll(headers);

      print('添加分片数据到请求');
      // 添加分片数据
      if (kIsWeb) {
        if (chunkData is Uint8List) {
          request.files.add(
            http.MultipartFile.fromBytes(
              'file',
              chunkData,
              filename: path.basename(filePath),
            ),
          );
        } else {
          throw Exception('Web平台上传分片需要提供字节数据');
        }
      } else {
        if (chunkData is Uint8List) {
          print('添加字节数据: ${chunkData.length} 字节');
          request.files.add(
            http.MultipartFile.fromBytes(
              'file',
              chunkData,
              filename: path.basename(filePath),
            ),
          );
        } else {
          throw Exception('上传分片需要提供字节数据');
        }
      }

      print('发送分片上传请求');
      // 发送请求
      var streamedResponse = await request.send();
      var response = await http.Response.fromStream(streamedResponse);

      // 如果返回401，尝试刷新令牌并重试
      if (response.statusCode == 401) {
        print('令牌已过期，尝试刷新...');
        await AuthService.refreshToken();

        // 使用新令牌重试请求
        headers = await AuthService.getAuthHeaders();
        request = http.MultipartRequest('POST', uri);
        request.headers.addAll(headers);

        if (kIsWeb) {
          if (chunkData is Uint8List) {
            request.files.add(
              http.MultipartFile.fromBytes(
                'file',
                chunkData,
                filename: path.basename(filePath),
              ),
            );
          }
        } else {
          if (chunkData is Uint8List) {
            request.files.add(
              http.MultipartFile.fromBytes(
                'file',
                chunkData,
                filename: path.basename(filePath),
              ),
            );
          }
        }

        streamedResponse = await request.send();
        response = await http.Response.fromStream(streamedResponse);
      }

      print('收到响应: ${response.statusCode}');
      print('响应内容: ${response.body}');

      final responseData = json.decode(utf8.decode(response.bodyBytes));
      print('解码响应数据: $responseData');

      // 处理错误响应
      if (response.statusCode != 200) {
        final errorMessage =
            responseData['detail'] ?? responseData['message'] ?? '未知错误';
        throw Exception(errorMessage);
      }

      final apiResponse = ApiResponse<ChunkUploadResponse>.fromJson(
        responseData,
        (data) => ChunkUploadResponse.fromJson(data as Map<String, dynamic>),
      );

      if (apiResponse.isSuccess) {
        print('分片上传成功');
        return apiResponse;
      } else {
        throw Exception(apiResponse.message);
      }
    } catch (e) {
      print('上传分片失败: $e');
      rethrow;
    }
  }

  /// 获取上传状态
  Future<ApiResponse<ChunkUploadStatusResponse>> getUploadStatus(
    String taskId,
  ) async {
    var uri = Uri.parse('$baseUrl/chunk-upload/status/$taskId');

    try {
      // 获取认证头
      var headers = await AuthService.getAuthHeaders();

      var response = await http.get(uri, headers: headers);

      // 如果返回401，尝试刷新令牌并重试
      if (response.statusCode == 401) {
        print('令牌已过期，尝试刷新...');
        await AuthService.refreshToken();

        // 使用新令牌重试请求
        headers = await AuthService.getAuthHeaders();
        response = await http.get(uri, headers: headers);
      }

      final responseData = json.decode(utf8.decode(response.bodyBytes));

      // 处理错误响应
      if (response.statusCode != 200) {
        final errorMessage =
            responseData['detail'] ?? responseData['message'] ?? '未知错误';
        throw Exception(errorMessage);
      }

      final apiResponse = ApiResponse<ChunkUploadStatusResponse>.fromJson(
        responseData,
        (data) =>
            ChunkUploadStatusResponse.fromJson(data as Map<String, dynamic>),
      );

      if (apiResponse.isSuccess) {
        return apiResponse;
      } else {
        throw Exception(apiResponse.message);
      }
    } catch (e) {
      print('获取上传状态失败: $e');
      rethrow;
    }
  }

  /// 完成上传
  Future<ApiResponse<ChunkUploadCompleteResponse>> completeUpload(
    String taskId,
  ) async {
    var uri = Uri.parse('$baseUrl/chunk-upload/complete');

    try {
      // 获取认证头
      var headers = await AuthService.getAuthHeaders();
      headers['Content-Type'] = 'application/json';

      var response = await http.post(
        uri,
        headers: headers,
        body: json.encode({'task_id': taskId}),
      );

      // 如果返回401，尝试刷新令牌并重试
      if (response.statusCode == 401) {
        print('令牌已过期，尝试刷新...');
        await AuthService.refreshToken();

        // 使用新令牌重试请求
        headers = await AuthService.getAuthHeaders();
        headers['Content-Type'] = 'application/json';

        response = await http.post(
          uri,
          headers: headers,
          body: json.encode({'task_id': taskId}),
        );
      }

      final responseData = json.decode(utf8.decode(response.bodyBytes));

      // 处理错误响应
      if (response.statusCode != 200) {
        final errorMessage =
            responseData['detail'] ?? responseData['message'] ?? '未知错误';
        throw Exception(errorMessage);
      }

      final apiResponse = ApiResponse<ChunkUploadCompleteResponse>.fromJson(
        responseData,
        (data) =>
            ChunkUploadCompleteResponse.fromJson(data as Map<String, dynamic>),
      );

      if (apiResponse.isSuccess) {
        return apiResponse;
      } else {
        throw Exception(apiResponse.message);
      }
    } catch (e) {
      print('完成上传失败: $e');
      rethrow;
    }
  }

  /// 取消上传
  Future<ApiResponse<AbortUploadResponse>> abortUpload(String taskId) async {
    var uri = Uri.parse('$baseUrl/chunk-upload/abort/$taskId');

    try {
      // 获取认证头
      var headers = await AuthService.getAuthHeaders();

      var response = await http.post(uri, headers: headers);

      // 如果返回401，尝试刷新令牌并重试
      if (response.statusCode == 401) {
        print('令牌已过期，尝试刷新...');
        await AuthService.refreshToken();

        // 使用新令牌重试请求
        headers = await AuthService.getAuthHeaders();
        response = await http.post(uri, headers: headers);
      }

      final responseData = json.decode(utf8.decode(response.bodyBytes));

      // 处理错误响应
      if (response.statusCode != 200) {
        final errorMessage =
            responseData['detail'] ?? responseData['message'] ?? '未知错误';
        throw Exception(errorMessage);
      }

      final apiResponse = ApiResponse<AbortUploadResponse>.fromJson(
        responseData,
        (data) => AbortUploadResponse.fromJson(data as Map<String, dynamic>),
      );

      if (apiResponse.isSuccess) {
        return apiResponse;
      } else {
        throw Exception(apiResponse.message);
      }
    } catch (e) {
      print('取消上传失败: $e');
      rethrow;
    }
  }

  /// 普通文件上传
  Future<ApiResponse<dynamic>> uploadFile({
    required String filePath,
    required int directoryId,
  }) async {
    // 将directory_id作为URL查询参数添加
    final uri = Uri.parse(
      '$baseUrl/upload',
    ).replace(queryParameters: {'directory_id': directoryId.toString()});

    try {
      // 获取认证头
      final headers = await AuthService.getAuthHeaders();

      // 创建multipart请求
      var request = http.MultipartRequest('POST', uri);
      request.headers.addAll(headers);

      // 读取文件
      final file = File(filePath);
      if (!await file.exists()) {
        throw Exception('文件不存在：$filePath');
      }

      // 添加文件到请求
      final fileLength = await file.length();

      // 标准上传方式
      final fileStream = http.ByteStream(file.openRead());
      final multipartFile = http.MultipartFile(
        'file',
        fileStream,
        fileLength,
        filename: file.path.split('/').last,
      );
      request.files.add(multipartFile);

      // 添加目录ID参数
      request.fields['directory_id'] = directoryId.toString();

      // 发送请求并获取响应
      final streamedResponse = await request.send();
      final response = await http.Response.fromStream(streamedResponse);

      // 如果返回401，尝试刷新令牌并重试
      if (response.statusCode == 401) {
        debugPrint('令牌已过期，尝试刷新...');
        await AuthService.refreshToken();

        // 使用新令牌重试请求
        debugPrint('令牌已刷新，重试上传请求');

        // 获取新的认证头
        final newHeaders = await AuthService.getAuthHeaders();

        // 创建新请求
        final newRequest = http.MultipartRequest('POST', uri);
        newRequest.headers.addAll(newHeaders);

        // 重新添加文件
        final newFileStream = http.ByteStream(file.openRead());
        final newMultipartFile = http.MultipartFile(
          'file',
          newFileStream,
          fileLength,
          filename: file.path.split('/').last,
        );
        newRequest.files.add(newMultipartFile);

        // 重新添加其他参数
        newRequest.fields['directory_id'] = directoryId.toString();

        // 发送新请求
        final newStreamedResponse = await newRequest.send();
        final newResponse = await http.Response.fromStream(newStreamedResponse);

        final responseData = json.decode(utf8.decode(newResponse.bodyBytes));

        return ApiResponse(
          code: newResponse.statusCode,
          message: '上传成功',
          data: responseData,
          timestamp: DateTime.now().toIso8601String(),
        );
      }

      print('收到响应: ${response.statusCode}');
      print('响应内容: ${response.body}');

      final responseData = json.decode(utf8.decode(response.bodyBytes));
      print('解码响应数据: $responseData');

      // 处理错误响应
      if (response.statusCode != 200) {
        final errorMessage =
            responseData['detail'] ?? responseData['message'] ?? '未知错误';
        throw Exception(errorMessage);
      }

      // 创建具有一致结构的响应
      return ApiResponse(
        code: 200,
        message: '上传成功',
        data: responseData['data'] ?? responseData, // 兼容两种响应格式
        timestamp: DateTime.now().toIso8601String(),
      );
    } catch (e) {
      print('上传文件失败: $e');
      rethrow;
    }
  }
}
